
import { _decorator, Component, Node, Pool, instantiate, Vec3, math } from 'cc';
import { Player } from '../player';

import { SpawnConfig, SpawnItem, SpawnItemData } from './SpawnConfig';
const { ccclass, property } = _decorator;

@ccclass('BuilderControl')
export class BuilderControl extends Component {

    //没有显示到面板上
    @property(SpawnConfig) spawnConfig: SpawnConfig = new SpawnConfig();

    startCreatePosZ = 0;
    private poolMap: Map<string, Pool<SpawnItem>> = new Map<string, Pool<SpawnItem>>();

    public endPosZ = 0;

    public recoveryItemArr: SpawnItem[] = [];

    public rcreateLength = 140;

    public recoveryOffset = -5;

    start() {
        // [3]

        for (let i = 0; i < this.spawnConfig.spawnItemDataArray.length; i++) {
            let spwanItemData = this.spawnConfig.spawnItemDataArray[i];
            this.poolMap.set(spwanItemData.prefab._uuid, new Pool<SpawnItem>(() => {
                return this.createSpawnItem(spwanItemData); //重点 Pool的第一个参数是Pool里面存的值，第二个值是Pool的容量
            }, 1))
        }
        this.startCreatePosZ = this.spawnConfig.startCreatePos;
    }

    update(dt: number) {

        //（前提是准备好的对象池 预制的uuid:对应其对象池 ）Pool 可以放带类型的对象{node,data:{prefab,nodelength}} spawnItem
        //思想是一直创建物体，镜头一直在向前移动
        //然后一直回收物体

        //创建物体一直到道路尽头 先给一段道路长度 startPos 
        //要有随机性 准备[]一个数组 随机出生成一个建筑，设置该建筑的位置z，就是

        //创建的物体会被回收，放入对象池中（如果该物体的z坐标 < 镜头的z坐标 镜头已经跑到前面，但是这些物体已经看不见了）

        this.createToEnd();
        this.recoverySpawnItem();

    }

    createSpawnItem(data: SpawnItemData) {
        let node = instantiate(data.prefab);
        let spwanItem = new SpawnItem();
        spwanItem.node = node;
        spwanItem.spawnItemData = data;
        //用于回收的数组
        this.recoveryItemArr.push(spwanItem);
        return spwanItem;
    }


    createToEnd() {

        this.GetEndPos();
        // 
        while (this.startCreatePosZ < this.endPosZ) {
            //创建
            //1.随机出一个spwanItemData
            // 2.从对象池中取出spawnIstem
            //3.然后设置起点，加入场景
            //4.放入待回收的数组
            // let itemIndex = parseInt(Math.random() * this.spawnConfig.spawnItemDataArray.length)

            //如果随机到的一个数据spawnItemData在POolMap是null 就会重新随机，只有成功了startCreatePosZ更新

            let spawnItem = this.doSpawnItem();
            if (spawnItem) {
                this.startCreatePosZ += spawnItem.spawnItemData.node_length;
            }

        }


    }

    doSpawnItem() {

        let randomIndex = math.randomRangeInt(0, this.spawnConfig.spawnItemDataArray.length);
        let spawnItemData = this.spawnConfig.spawnItemDataArray[randomIndex];
        let item = this.poolMap.get(spawnItemData.prefab._uuid)?.alloc();
        //注意非空判断
        if (item != null) {
            // node.active = true;
            let node = item.node;
            this.node.scene.addChild(node);
            // 把属性设置提取出来 障碍物的位置生成和奖励的生成逻辑和建筑物的生成基本一样 但是生成规则不同而已
            this.onSpawn(node, item.spawnItemData)
        }
        return item;

    }

    onSpawn(node: Node, spawnItemData: SpawnItemData) {
        node.setPosition(new Vec3(0, 0, this.startCreatePosZ));
        let newSpawnItem = new SpawnItem();
        node.active = true;
        newSpawnItem.node = node;
        newSpawnItem.spawnItemData = spawnItemData;
        this.recoveryItemArr.push(newSpawnItem);


    }


    GetEndPos() {
        this.endPosZ = Player.instance.curPosZ + this.rcreateLength;
        // 
    }

    //回收镜头外的node 
    //出现bug的原因是一直往 recoverySpawnItem 中push   导致有些节点在场景中被提前回收，给回收了的node的active设置为false
    recoverySpawnItem() {
        for (const spawn_item of this.recoveryItemArr) {

            //node.isValide判断节点是否已经被销毁，如果只是放在节点池中 isValid是true 
            if (spawn_item.node.active) {

                //卡在这里 跑出镜头 镜头的位置是 Player.instance.curPosZ，建筑物的pos的终点超出<镜头的位置才是跑出尽头
                let length = spawn_item.spawnItemData.node_length;
                if (spawn_item.node.getPosition().z + length < Player.instance.curPosZ + this.recoveryOffset) {
                    this.poolMap.get(spawn_item.spawnItemData.prefab._uuid)?.free(spawn_item);
                    // this.recoveryItemArr.pop()
                    // console.log('this.recoveryItemArr', this.recoveryItemArr)
                    spawn_item.node.active = false;
                }
            }

        }
    }


}


